/*****************************************************************************
 * plum_socket.h
 *
 * Copyright (C) 2020 Jeasonvor 1101627719@qq.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 ****************************************************************************/
#ifndef __PLUM_SOCKET_H__
#define __PLUM_SOCKET_H__

/*****************************************************************************
 * Included Files
 ****************************************************************************/
#if !defined(PLUM_API_INCLUDE)
#error "Only 'plum_api.h' can be include directly"
#endif
/*****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/
#define PLUM_ADDR_MAX_LEN 96

#define PLUM_IPADDR_INIT_IPV4(ipaddrp, addr, port) \
    plum_ipaddr_init(ipaddrp, PLUM_SOCKET_FAMILY_AF_INET, addr, port)

#define PLUM_IPADDR_INIT_IPV6(ipaddrp, addr, port) \
    plum_ipaddr_init(ipaddrp, PLUM_SOCKET_FAMILY_AF_INET6, addr, port)

#define PLUM_IPADDR_INIT_UNIX(ipaddrp, addr, port) \
    plum_ipaddr_init(ipaddrp, PLUM_SOCKET_FAMILY_AF_UNIX, addr, port)

/*****************************************************************************
 * Public Types
 ****************************************************************************/

/**
 * @brief：地址协议簇AF(address family)
 */
typedef enum {
    PLUM_ADDRESS_FAMILY_AF_UNSPEC = 0,
    PLUM_ADDRESS_FAMILY_AF_UNIX   = 2, /** 本地通讯 */
    PLUM_ADDRESS_FAMILY_AF_INET   = 3, /** IPv4    */
    PLUM_ADDRESS_FAMILY_AF_INET6  = 4, /** IPv6    */
    PLUM_ADDRESS_FAMILY_AF_PACKET = 5, /** 底层包访问  */
} plum_socket_addr_family_t;

/**
 * @brief: 套接字类型
 */
typedef enum {
    PLUM_SOCKET_TYPE_TCP,       /** tcp     */
    PLUM_SOCKET_TYPE_UDP,       /** udp     */
    PLUM_SOCKET_TYPE_RAW,       /** RAW     */
    PLUM_SOCKET_TYPE_SEQPACKET, /** seqpacket */
} plum_socket_type_t;

typedef struct {
    plum_socket_addr_family_t family;
    plum_s8                   addr[PLUM_ADDR_MAX_LEN];
    plum_u16                  port;
} plum_ipaddr_t;

typedef plum_u32 plum_socket_t;
/*****************************************************************************
 * Public Data
 ****************************************************************************/

/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/**
 * @brief:  IP地址初始化
 *
 * @param[out]: ipaddr      -   ip地址指针
 * @param[in]:  family      -   协议簇
 * @param[in]:  addr        -   ip地址字符串
 * @param[in]:  port        -   端口
 *
 * @return:
 * **/
PLUM_INLINE
plum_void plum_ipaddr_init(plum_ipaddr_t *           ipaddr,
                           plum_socket_addr_family_t family,
                           PLUM_CONST plum_s8 *addr, plum_u16 port)
{
    ipaddr->family = family;
    ipaddr->port   = port;
    snprintf(ipaddr->addr, sizeof(ipaddr->addr), "%s", addr);
}

/**
 * @brief:  获取IP地址
 *
 * @param[in]:  domain      -   域
 * @param[in]:  ipaddr      -   IP地址字符串
 *
 * @return: 返回错误码
 * **/
plum_s32 plum_dns_get_hostname(PLUM_CONST plum_s8 *domain, plum_s8 *ipaddr);

/**
 * @brief:  创建socket套接字
 *
 * @param[in]: family       -   地址类型
 * @param[in]: type         -   套接字类型
 *
 * @return：    成功    -   返回套接字描述符
 *              失败    -   返回错误码
 */
plum_s32 plum_cal_socket_create(plum_socket_addr_family_t family,
                                plum_socket_type_t        type);

/**
 * @brief:  绑定套接字
 *
 * @param[in]:   socketfd       -   套接字描述符
 * @param[in]:   addr           -   待绑定地址(本端地址)
 *
 * @return：返回执行状态
 */
plum_s32 plum_cal_socket_bind(plum_u32 socketfd, plum_ipaddr_t addr);

/**
 * @brief:  通过socket连接
 *
 * @param:  socekfd     -   套接字句柄
 * @param:  addr        -   待连接地址（对端地址）
 *
 * @return: 返回执行状态
 */
plum_s32 plum_cal_socket_connect(plum_u32 socekfd, plum_ipaddr_t addr);

/**
 * @brief： 监听端口
 *
 * @param[in]： socketfd        -   socket套接字
 * @param[in]： max             -   最大监听数量
 *
 * @return：    返回执行状态
 */
plum_s32 plum_cal_socket_listen(plum_u32 socketfd, plum_u32 max);

/**
 * @brief:  接收客户端请求
 *
 * @param[in]:   socektfd       -   本地套接字描述符
 * @param[out]： addr           -   对端地址信息
 *
 * @return：    成功    -   返回与对端建立连接的套接字
 *              失败    -   返回错误码
 */
plum_s32 plum_cal_socket_accept(plum_u32 socektfd, plum_ipaddr_t *addr);

/**
 * @brief:  接收socket消息
 *
 * @param[in]:  socektfd    -   套接字
 * @param[out]: data        -   接收数据指针
 * @param[in]:  size        -   待接收数据字节长度
 * @param[in]:  timeout     -   超时时间(ms)
 *
 * @return: 成功    -   返回接收到的数据长度
 *          失败    -   返回错误码
 */
plum_s32 plum_cal_socket_recv(plum_u32 socektfd, plum_void *data, plum_u32 size,
                              plum_u32 timeout);

/**
 * @brief:  发送socket消息
 *
 * @param[in]:  socektfd    -   套接字
 * @param[in]:  data        -   待发送数据指针
 * @param[in]:  size        -   待接收数据字节长度
 *
 * @return: 成功    -   返回实际发送的数据长度
 *          失败    -   返回错误码
 */
plum_s32 plum_cal_socekt_send(plum_u32 socektfd, plum_void *data,
                              plum_u32 size);

/**
 * @brief:  关闭套接字
 *
 * @return:
 */
plum_void plum_cal_socekt_close(plum_u32 socktfd);

/****************************************************************************/
#ifdef __cplusplus
}
#endif
/****************************************************************************/
#endif /* __PLUM_SOCKET_H__ */
/****************************************************************************/
/*                                                                          */
/*  End of file.                                                            */
/*                                                                          */
/****************************************************************************/
